package com.daxue.configtest.exception;

import java.beans.ConstructorProperties;
import java.util.function.Function;

/**
 * @author daxue0929
 * @date 2023/3/26
 */

public class ExceptionWrapper extends RuntimeException{
    private Throwable origin;

    public <T extends Throwable> T unwrap() {
        return (T) this.origin;
    }

    @ConstructorProperties({"origin"})
    private ExceptionWrapper(final Throwable origin) {
        this.origin = origin;
    }

    public static ExceptionWrapper of(final Throwable origin) {
        return new ExceptionWrapper(origin);
    }

    @FunctionalInterface
    public interface ConsumerWrapFunction {
        void accept() throws Throwable;

        static void wrap(ExceptionWrapper.ConsumerWrapFunction wrapFunction) throws ExceptionWrapper {
            wrap(wrapFunction, ExceptionWrapper::of, false);
        }

        static <E extends RuntimeException> void wrap(ExceptionWrapper.ConsumerWrapFunction wrapFunction, Function<Throwable, E> exceptionWrapper) throws E {
            wrap(wrapFunction, exceptionWrapper, false);
        }

        static <E extends RuntimeException> void wrap(ExceptionWrapper.ConsumerWrapFunction wrapFunction, boolean escapeWrappable) throws E {
            wrap(wrapFunction, ExceptionWrapper::of, escapeWrappable);
        }

        static <E extends RuntimeException> void wrap(ExceptionWrapper.ConsumerWrapFunction wrapFunction, Function<Throwable, E> exceptionWrapper, boolean escapeWrappable) throws E {
            try {
                wrapFunction.accept();
            } catch (Throwable var4) {
                if (escapeWrappable && var4 instanceof WrappableException) {
                    throw ((WrappableException)var4).wrap();
                } else {
                    throw (RuntimeException)exceptionWrapper.apply(var4);
                }
            }
        }
    }

    @FunctionalInterface
    public interface SupplierWrapFunction<T> {
        T get() throws Throwable;

        static <R> R wrap(ExceptionWrapper.SupplierWrapFunction<R> wrapFunction) throws ExceptionWrapper {
            return wrap(wrapFunction, ExceptionWrapper::of, false, false);
        }

        static <R, E extends RuntimeException> R wrap(ExceptionWrapper.SupplierWrapFunction<R> wrapFunction, Function<Throwable, E> exceptionWrapper) throws E {
            return wrap(wrapFunction, exceptionWrapper, false, false);
        }

        /** @deprecated */
        @Deprecated
        static <R, E extends RuntimeException> R wrap(ExceptionWrapper.SupplierWrapFunction<R> wrapFunction, boolean escapeWrappable) throws E {
            return wrap(wrapFunction, ExceptionWrapper::of, escapeWrappable, false);
        }

        static <R, E extends RuntimeException> R wrap(ExceptionWrapper.SupplierWrapFunction<R> wrapFunction, boolean escapeWrappable, boolean escapeRuntime) throws E {
            return wrap(wrapFunction, ExceptionWrapper::of, escapeWrappable, escapeRuntime);
        }

        /** @deprecated */
        @Deprecated
        static <R, E extends RuntimeException> R wrap(ExceptionWrapper.SupplierWrapFunction<R> wrapFunction, Function<Throwable, E> exceptionWrapper, boolean escapeWrappable) throws E {
            return wrap(wrapFunction, exceptionWrapper, escapeWrappable, false);
        }

        static <R, E extends RuntimeException> R wrap(ExceptionWrapper.SupplierWrapFunction<R> wrapFunction, Function<Throwable, E> exceptionWrapper, boolean escapeWrappable, boolean escapeRuntime) {
            try {
                return wrapFunction.get();
            } catch (Throwable var5) {
                if (escapeWrappable && var5 instanceof WrappableException) {
                    throw ((WrappableException)var5).wrap();
                } else if (escapeRuntime && var5 instanceof RuntimeException) {
                    throw (RuntimeException)var5;
                } else {
                    throw (RuntimeException)exceptionWrapper.apply(var5);
                }
            }
        }
    }
}
